package com.wdd.myplatform.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * redis锁测试
 */
@RestController
@RequestMapping("/redisLock")
public class RedisLockController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private final String LOCK_TEST = "lock_test";

    private String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";

    private static final Long RELEASE_SUCCESS = 1L;

    ExecutorService pool = Executors.newFixedThreadPool(10);

    /**
     * 尝试获取锁 立即返回
     *
     * @param key
     * @param value
     * @param timeout
     * @return
     */
    public boolean lock(String key, String value, long timeout) {
        return stringRedisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.MILLISECONDS);
    }

    @GetMapping("/lock")
    public void testLock(){
        for (int i = 0; i < 10; i++) {
            pool.execute(()->{
                String value = Thread.currentThread()+String.valueOf(System.currentTimeMillis());
                try {
                    Boolean ifAbsent = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_TEST, value, 60, TimeUnit.SECONDS);
                    //加锁成功做业务处理
                    if(ifAbsent){
                        System.out.println(Thread.currentThread()+"加锁成功");
                        Thread.sleep(1000);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    unlock(LOCK_TEST,value);
                }
            });
        }
    }

    public boolean unlock(String key, String value) {
        DefaultRedisScript<Long> redisScript = defaultRedisScript();
        List list = new ArrayList<>();
        list.add(key);
        //使用Lua脚本：先判断是不是本身设置的锁，再执行删除
        Long result = stringRedisTemplate.execute(redisScript, list,value);
        //返回最终结果
        if(RELEASE_SUCCESS.equals(result)){
            System.out.println(Thread.currentThread()+"删除锁成功");
            return true;
        }
        return false;
    }

    private DefaultRedisScript<Long> defaultRedisScript() {
        DefaultRedisScript<Long> defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setResultType(Long.class);
        defaultRedisScript.setScriptText("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end");
        return defaultRedisScript;
    }

}
